package org.devocean.groupbuying.dao.impl;

import java.text.Normalizer;
import java.text.Normalizer.Form;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.devocean.groupbuying.dao.PlanDAO;
import org.devocean.groupbuying.domain.Article;
import org.devocean.groupbuying.domain.Plan;
import org.springframework.stereotype.Repository;

@Repository
public class PlanDAOImpl implements PlanDAO {

	@PersistenceContext
	private EntityManager em;

	public void linkToArticle(Plan plan) {
		for (Article article : plan.getArticlesLocalization().getArticles()) {
			article.setArticlesLocalization(plan.getArticlesLocalization());
		}
	}
	
	private String slugify(String string) {
		return Normalizer.normalize(string.toLowerCase(), Form.NFD)
				.replaceAll("\\p{InCombiningDiacriticalMarks}+", "")
				.replaceAll("[^\\p{Alnum}]+", "_");
	}

	public List<Plan> findAllPlans() {
		return em.createQuery("SELECT pl from Plan pl", Plan.class)
				.getResultList();
	}

	public List<Plan> findAllPlans(String lang) {

		final Query query = em
				.createQuery("SELECT DISTINCT pl FROM Plan pl "
						+ "INNER JOIN FETCH pl.formulas f "
						+ "INNER JOIN FETCH f.discount di "
						+ "INNER JOIN FETCH di.deal d "
						+ "LEFT JOIN FETCH pl.promotions pr "
						+ "INNER JOIN FETCH pl.product p "
						+ "INNER JOIN FETCH p.articlesLocalization pal "
						+ "INNER JOIN FETCH pal.articles pala "
						+ "INNER JOIN FETCH pl.articlesLocalization plal "
						+ "INNER JOIN FETCH plal.articles plala "
						+ "WHERE pala.lang=:lang AND plala.lang=:lang" + "",
						Plan.class);
		query.setParameter("lang", lang);
		return query.getResultList();
	}

	public long countPlans() {
		try {
			return em.createQuery("SELECT COUNT(pl) FROM Plan pl", Long.class)
					.getSingleResult();
		} catch (Exception e) {
			System.out.println(e.getMessage());
			return 1;
		}
		
	}

	public List<Plan> findPlansEntries(int firstResult, int maxResults) {
		return em.createQuery("SELECT pl FROM Plan pl", Plan.class)
				.setFirstResult(firstResult).setMaxResults(maxResults)
				.getResultList();
	}

	public Plan findPlanById(Integer id) {
		return em.find(Plan.class, id);
	}

	public void removePlan(int id) {
		final Plan plan = em.find(Plan.class, id);

		if (plan != null) {

			em.remove(plan);
		}
	}

	public Plan savePlan(Plan plan) {
		if (plan.getArticlesLocalization().getArticlesLocalizationID() == null) {
			String title = plan.getArticlesLocalization().getArticles()
					.iterator().next().getTitle();
			plan.getArticlesLocalization().setPermalink(this.slugify(title));
		}
		this.linkToArticle(plan);
		em.persist(plan);
		return plan;

	}

	public Plan updatePlan(Plan plan) {
		this.linkToArticle(plan);
		final Plan merged = em.merge(plan);
		return merged;
	}

	public List<Plan> findPlansByProduct(Integer productID, String lang) {
		try {
			return em
					.createQuery(
							"SELECT DISTINCT pl from Plan pl"
									+ " INNER JOIN FETCH pl.articlesLocalization al"
									+ " INNER JOIN FETCH pl.product p"
									+ " LEFT JOIN FETCH pl.formulas fo"
									+ " INNER JOIN FETCH al.articles a where p.productID = :id and a.lang = :lang ",
							Plan.class).setParameter("id", productID)
					.setParameter("lang", lang).getResultList();
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}

		return null;

	}

	public Plan findPlanByArticle(Integer articleID) {

		return em
				.createQuery(
						"SELECT p from Plan p "
								+ "INNER JOIN FETCH p.articlesLocalization al "
								+ "INNER JOIN FETCH p.product pr"
								+ " LEFT JOIN FETCH p.formulas f"
								+ "INNER JOIN FETCH al.articles a where a.articleID = :id  ",
						Plan.class).setParameter("id", articleID)
				.getSingleResult();

	}

	public Plan findPlanByLang(Integer localizationKey,
			String localizationRequest) {
		try {
			return em
					.createQuery(
							"SELECT  p from Plan p"
									+ " INNER JOIN FETCH p.articlesLocalization al"
									+ " INNER JOIN FETCH al.articles a"
									+ " where a.articlesLocalization.articlesLocalizationID=:localization and a.lang=:lang",
							Plan.class)
					.setParameter("localization", localizationKey)
					.setParameter("lang", localizationRequest).getResultList()
					.get(0);
		} catch (IndexOutOfBoundsException e) {
			return null;
		}

	}

	public Plan findPlanByArticleLocalization(Integer localizationKey) {
		return em
				.createQuery(
						"SELECT p  FROM Plan p where p.articlesLocalization.articlesLocalizationID=:al",
						Plan.class).setParameter("al", localizationKey)
				.getSingleResult();
	}

}
